#include "data_shared.h"
#include "nvs_operator.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "esp_log.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"

#include "carray.h"
#include "queue.h"

#define TAG "data-shared"
#define PV_DATA_COUNT 40
static int _count = 0;
static queue _pv_queue;
static uint32_t _out = 0;
static float _input = 0;
static pid_cache_t _pid_cache = {0};
static uint32_t _pv_data_u32[PV_DATA_COUNT] = {0};
static int _pv_data_i[PV_DATA_COUNT] = {0};
static bool _autotune_state = false;
void db_init()
{
    nvs_op_init();

    _pv_queue = newQueue();
    _pid_cache.sv = 20;
    _pid_cache.kp = 1;
    _pid_cache.ki = 1;
    _pid_cache.kd = 1;
    _pid_cache.out_max = 1;
    _pid_cache.out_min = 1;
    _pid_cache.out_time_ms = 1;

    nvs_op_get_float_value("sv", &_pid_cache.sv, 20);
    nvs_op_get_float_value("kp", &_pid_cache.kp, 1);
    nvs_op_get_float_value("ki", &_pid_cache.ki, 0);
    nvs_op_get_float_value("kd", &_pid_cache.kd, 0);
    nvs_op_get_float_value("out_max", &_pid_cache.out_max, 1);
    nvs_op_get_float_value("out_min", &_pid_cache.out_min, 0);
    nvs_op_get_u32_value("out_time_ms", &_pid_cache.out_time_ms, 2000);
}
void db_add_data(float value)
{
    _input = value;
    if (_pv_queue->length >= PV_DATA_COUNT)
    {
        QueueDequeue(_pv_queue);
    }
    QueueEnqueue(_pv_queue, (int)_input);
}
void db_get_data(int *data, int *size)
{

    QueueGetValue(_pv_queue, _pv_data_i, &_count);
    for (int i = 0; i < PV_DATA_COUNT; i++)
    {
        data[i] = _pv_data_i[i];
        *size = i + 1;
    }
}
void db_get_u32_data(uint32_t *data, int *size)
{
    QueueGetValue(_pv_queue, _pv_data_i, &_count);
    for (int i = 0; i < PV_DATA_COUNT; i++)
    {
        data[i] = (uint32_t)_pv_data_i[i];
        *size = i + 1;
    }
}
void db_clear()
{
}

float db_get_input()
{
    return _input;
}
void db_set_input(float value)
{
    _input = value;
}

uint32_t db_get_output()
{
    return _out;
}
void db_set_output(uint32_t value)
{
    _out = value;
}

void db_get_pid_cache(pid_cache_t *cache)
{
    cache->sv = _pid_cache.sv;
    cache->kp = _pid_cache.kp;
    cache->ki = _pid_cache.ki;
    cache->kd = _pid_cache.kd;
    cache->out_max = _pid_cache.out_max;
    cache->out_min = _pid_cache.out_min;
    cache->out_time_ms = _pid_cache.out_time_ms;
}
void db_set_pid_cache(const pid_cache_t *cache)
{
    _pid_cache.sv = cache->sv;
    _pid_cache.kp = cache->kp;
    _pid_cache.ki = cache->ki;
    _pid_cache.kd = cache->kd;
    _pid_cache.out_max = cache->out_max;
    _pid_cache.out_min = cache->out_min;
    _pid_cache.out_time_ms = cache->out_time_ms;
    nvs_op_set_float_value("sv", _pid_cache.sv);
    nvs_op_set_float_value("kp", _pid_cache.kp);
    nvs_op_set_float_value("ki", _pid_cache.ki);
    nvs_op_set_float_value("kd", _pid_cache.kd);
    nvs_op_set_float_value("out_max", _pid_cache.out_max);
    nvs_op_set_float_value("out_min", _pid_cache.out_min);
    nvs_op_set_u32_value("out_time_ms", _pid_cache.out_time_ms);
}
void db_set_autotune_state(bool state)
{
    _autotune_state = state;
}

bool db_get_autotune_state()
{
    return _autotune_state;
}